From 840e884874a68af21d9042061ccaa548d435bf04 Mon Sep 17 00:00:00 2001 From: tsteven4 <13596209+tsteven4@users.noreply.github.com> Date: Sat, 18 Nov 2023 06:59:38 -0700 Subject: [PATCH] convert tpo formats to Format class (#1225) * convert tpo to Format class. * capture comments --- CMakeLists.txt | 1 + tpo.cc | 123 +++++++--------------------- tpo.h | 213 +++++++++++++++++++++++++++++++++++++++++++++++++ vecs.cc | 7 +- 4 files changed, 247 insertions(+), 97 deletions(-) create mode 100644 tpo.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 995f6b724..9e4a6ee5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -237,6 +237,7 @@ set(HEADERS skytraq.h subrip.h text.h + tpo.h unicsv.h units.h vcf.h diff --git a/tpo.cc b/tpo.cc index dd5a7ab7b..d15b1a512 100644 --- a/tpo.cc +++ b/tpo.cc @@ -69,9 +69,11 @@ 3.x "recreation" */ -#include // for abs +#include "tpo.h" + #include // for uint8_t #include // for printf, SEEK_CUR, SEEK_SET +#include // for abs #include // for strlen, strncmp #include // for vector @@ -79,41 +81,24 @@ #include // for QScopedArrayPointer #include // for QString #include // for qMakeStringPrivate, QStringLiteral -#include // for QVector #include // for qPrintable, Q_UNUSED -#include "defs.h" -#include "gbfile.h" // for gbfread, gbfgetc, gbfgetint32, gbfreadbuf, gbfseek, gbfgetdbl, gbfgetint16, gbfclose, gbfgetnativecstr, gbfgetuint16, gbfopen_le, gbfile +#include "defs.h" // for Waypoint, fatal, route_head, le_read32, waypt_add, track_add_wpt, track_add_head, xfree, xmalloc, doing_rtes, doing_wpts, gb_color, route_add_head, route_add_wpt, unknown_alt, doing_trks +#include "gbfile.h" // for gbfread, gbfgetc, gbfgetint32, gbfreadbuf, gbfseek, gbfgetdbl, gbfgetint16, gbfclose, gbfgetnativecstr, gbfgetuint16, gbfopen_le #include "jeeps/gpsmath.h" // for GPS_Math_Known_Datum_To_WGS84_M #define MYNAME "TPO" -static char* dumpheader = nullptr; - -static -QVector tpo2_args = { -}; - -static -QVector tpo3_args = { -}; - - -static gbfile* tpo_file_in; -static double track_length; /*******************************************************************************/ /* READ */ /*******************************************************************************/ -/* Define a global here that we can query from multiple places */ -static float tpo_version = 0.0; - /* tpo_check_version_string() Check the first bytes of the file for a version 3.0 header. */ -static void -tpo_check_version_string() +void +TpoFormatBase::tpo_check_version_string() { unsigned char string_size; @@ -142,11 +127,11 @@ tpo_check_version_string() } } -static void /* tpo_dump_header_bytes(int header_size) Write the first header_size bytes of the file to standard output as a C array definition. */ -tpo_dump_header_bytes(int header_size) +void +TpoFormatBase::tpo_dump_header_bytes(int header_size) { QByteArray buffer = gbfreadbuf(header_size, tpo_file_in); @@ -172,8 +157,8 @@ tpo_dump_header_bytes(int header_size) Keep reading bytes from the file until the section name is encountered, then go seek_bytes forwards (+) or backwards (-) to the start of the section data. */ -static void -tpo_read_until_section(const char* section_name, int seek_bytes) +void +TpoFormatBase::tpo_read_until_section(const char* section_name, int seek_bytes) { char byte; unsigned int match_index = 0; @@ -220,7 +205,7 @@ tpo_read_until_section(const char* section_name, int seek_bytes) // that is the only type of data available in the version 2.x TPO // files. // -static void tpo_read_2_x() +void TpoFormatBase::tpo_read_2_x() { char buff[16]; @@ -335,7 +320,7 @@ static void tpo_read_2_x() // // For version 3.x files. // -static int tpo_read_int() +int TpoFormatBase::tpo_read_int() { constexpr int debug = 0; @@ -381,7 +366,7 @@ static int tpo_read_int() // // For version 3.x/4.x files. // -static int tpo_find_block(unsigned int block_desired) +int TpoFormatBase::tpo_find_block(unsigned int block_desired) { unsigned int block_type; constexpr int debug = 0; @@ -419,7 +404,7 @@ static int tpo_find_block(unsigned int block_desired) // // For version 3.x files. // -static Waypoint* tpo_convert_ll(int lat, int lon) +Waypoint* TpoFormatBase::tpo_convert_ll(int lat, int lon) { auto* waypoint_temp = new Waypoint; @@ -453,19 +438,9 @@ static Waypoint* tpo_convert_ll(int lat, int lon) return (waypoint_temp); } -#define TRACKNAMELENGTH 255 -class StyleInfo -{ -public: - QString name; - uint8_t color[3] {0, 0, 0}; // keep R/G/B values separate because line_color needs BGR - uint8_t wide{0}; - uint8_t dash{0}; -}; - // Track decoder for version 3.x/4.x files. // This block contains tracks (called "freehand routes" in Topo). -static void tpo_process_tracks() +void TpoFormatBase::tpo_process_tracks() { constexpr int debug = 0; // 0-4 for increasingly verbose output in this subroutine) @@ -611,7 +586,7 @@ static void tpo_process_tracks() track_style -= 1; // STARTS AT 1, whereas style arrays start at 0 // Can be 8/16/32-bit value - never used? length in meters? - track_length = tpo_read_int(); + double track_length = tpo_read_int(); //UNKNOWN DATA LENGTH unsigned int name_length = tpo_read_int(); @@ -1039,17 +1014,9 @@ static void tpo_process_tracks() } // end of tpo_process_tracks -// Global index to waypoints, needed for routes, filled in by -// tpo_process_waypoints. -// -// For version 3.x files. -// -static Waypoint** tpo_wp_index; -static unsigned int tpo_index_ptr; - // Waypoint decoder for version 3.x files. // -static void tpo_process_waypoints() +void TpoFormatBase::tpo_process_waypoints() { //printf("Processing Waypoints...\n"); @@ -1157,7 +1124,7 @@ static void tpo_process_waypoints() // Map Notes decoder for version 3.x files. // -static void tpo_process_map_notes() +void TpoFormatBase::tpo_process_map_notes() { //printf("Processing Map Notes...\n"); @@ -1255,7 +1222,7 @@ static void tpo_process_map_notes() // Symbols decoder for version 3.x files. // -static void tpo_process_symbols() +void TpoFormatBase::tpo_process_symbols() { //printf("Processing Symbols...\n"); @@ -1298,7 +1265,7 @@ static void tpo_process_symbols() // Text Labels decoder for version 3.x files. // -static void tpo_process_text_labels() +void TpoFormatBase::tpo_process_text_labels() { //printf("Processing Text Labels...\n"); @@ -1362,7 +1329,7 @@ static void tpo_process_text_labels() // with pointers to waypoint objects by tpo_process_waypoints() // function above. // -static void tpo_process_routes() +void TpoFormatBase::tpo_process_routes() { //printf("Processing Routes...\n"); @@ -1446,7 +1413,7 @@ static void tpo_process_routes() #ifdef DEAD_CODE_IS_REBORN // Compass decoder for version 3.x files. // -static void tpo_process_compass() +void TpoFormatBase::tpo_process_compass() { // Not implemented yet @@ -1461,7 +1428,7 @@ static void tpo_process_compass() // (called "freehand routes" or just "routes" in Topo), "waypoints", // and "gps-routes". We intend to read all three types. // -static void tpo_read_3_x() +void TpoFormatBase::tpo_read_3_x() { if (doing_trks) { @@ -1517,8 +1484,8 @@ static void tpo_read_3_x() -static void -tpo_rd_init(const QString& fname) +void +TpoFormatBase::tpo_rd_init(const QString& fname) { // prepare for an attempt to deallocate memory that may or may not get allocated @@ -1547,8 +1514,8 @@ tpo_rd_init(const QString& fname) } } -static void -tpo_rd_deinit() +void +TpoFormatBase::tpo_rd_deinit() { // Free the waypoint index, we don't need it anymore. for (unsigned int i = 0; i < tpo_index_ptr; i++) { @@ -1565,8 +1532,8 @@ tpo_rd_deinit() gbfclose(tpo_file_in); } -static void -tpo_read() +void +TpoFormatBase::tpo_read() { if (tpo_version == 2.0) { @@ -1579,33 +1546,3 @@ tpo_read() fatal(MYNAME ": gpsbabel can only read TPO versions through 3.x.x\n"); } } - -/* TPO 2.x format can read tracks only */ -ff_vecs_t tpo2_vecs = { - ff_type_file, /* ff_type_internal */ - { ff_cap_none, ff_cap_read, ff_cap_none }, - tpo_rd_init, - nullptr, - tpo_rd_deinit, - nullptr, - tpo_read, - nullptr, - nullptr, - &tpo2_args, - NULL_POS_OPS -}; - -/* TPO 3.x format can read waypoints/tracks/routes */ -ff_vecs_t tpo3_vecs = { - ff_type_file, /* ff_type_internal */ - { ff_cap_read, ff_cap_read, ff_cap_read }, - tpo_rd_init, - nullptr, - tpo_rd_deinit, - nullptr, - tpo_read, - nullptr, - nullptr, - &tpo3_args, - NULL_POS_OPS -}; diff --git a/tpo.h b/tpo.h new file mode 100644 index 000000000..43a0c7e40 --- /dev/null +++ b/tpo.h @@ -0,0 +1,213 @@ +/* + National Geographic Topo! TPO file support. + 2.x support contributed to gpsbabel by Steve Chamberlin. + 3.x support contributed to gpsbabel by Curt Mills. + 4.x files read properly when treated as 3.x (final release was 4.5) + track parsing bugs fixed by Steve Eckert in 2012 and 2020 + + Topo! version 2.x: Tracks are implemented. + Topo! version 3.x/4.x: Reading of Tracks/Waypoints/Routes is + implemented. Also extracts Map Notes/ + Symbols/Text Labels as Waypoints. + + Copyright (C) 2005 Steve Chamberlin, slc at alum.mit.edu + Portions Copyright (C) 2006 Curtis E. Mills, archer at eskimo dot com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + */ + +/* + TPO format notes: + ----------------- + Most of the ASCII strings embedded in the text will have a + byte-count prepended to the string. Unknown yet whether other + fields have this same byte-count, but so far it doesn't look like + it. + + New format (3.x and later) files begin with a string byte-count + byte and then a string starting with "TOPO! Ver. 3.", like "TOPO! + Ver. 3.3.4". Can contain routes/tracks/waypoints, embedded + images, Map Notes, Symbols, Text Labels, Compass symbols, and + several others. + + Older (pre-3.0) format does not have the above string. Contains + only tracks. Waypoints are saved in a separate .TPG file. + + Track parsing has been problematic and may still not be right! + See further notes and clues in tpo_process_tracks() + (can #define Tracks2012 to revert to pre-2020 code in tpo_process_tracks) + + May contain these strings: + Frmt: String: + ----- -------------------------------- + 2.x "CTopoAzimuth" + 2.x "CTopoBookmark" + 2.x "CTopoGpsRoute". Saved in .tpg files (see tpg.c) + 2.x "CTopoRoute". The actual tracks we parse here. + 2.x "CTopoSymbol" + 2.x/3.x "CTopoText" + 2.x "CTopoWaypoint". Saved in .tpg files (see tpg.c) + 3.x "Notes" + 3.x "PNG." Embedded PNG image containing 2 rows of 40 + symbols each. Starts with signature: 89 50 4e 47 0d + 0a 1a 0a, ends with signature 49 45 4e 44 ae 42 60 82. + 3.x "shapes" + 3.x "arrows" + 3.x "recreation" +*/ +#ifndef TPO_H_INCLUDED_ +#define TPO_H_INCLUDED_ + +#include // for QString +#include // for QVector +#include // for uint8_t +#include "defs.h" // for ff_cap, arglist_t, ff_cap_none, ff_cap_read, Waypoint, ff_type, ff_type_file +#include "format.h" // for Format +#include "gbfile.h" // for gbfile + + +class TpoFormatBase +{ +protected: + /* Constants */ + + static constexpr int TRACKNAMELENGTH = 255; + + /* Types */ + + class StyleInfo + { + public: + QString name; + uint8_t color[3] {0, 0, 0}; // keep R/G/B values separate because line_color needs BGR + uint8_t wide{0}; + uint8_t dash{0}; + }; + + /* Member Functions */ + + void tpo_check_version_string(); + void tpo_dump_header_bytes(int header_size); + void tpo_read_until_section(const char* section_name, int seek_bytes); + void tpo_read_2_x(); + int tpo_read_int(); + int tpo_find_block(unsigned int block_desired); + static Waypoint* tpo_convert_ll(int lat, int lon); + void tpo_process_tracks(); + void tpo_process_waypoints(); + void tpo_process_map_notes(); + void tpo_process_symbols(); + void tpo_process_text_labels(); + void tpo_process_routes(); + void tpo_read_3_x(); + void tpo_rd_init(const QString& fname); + void tpo_rd_deinit(); + void tpo_read(); + + /* Data Members */ + + char* dumpheader = nullptr; + gbfile* tpo_file_in{}; + + // Define a global here that we can query from multiple places. + float tpo_version = 0.0; + + // Global index to waypoints, needed for routes, filled in by + // tpo_process_waypoints. + // + // For version 3.x files. + Waypoint** tpo_wp_index{}; + unsigned int tpo_index_ptr{}; +}; + +class Tpo2Format : public Format, private TpoFormatBase +{ +public: + QVector* get_args() override + { + return &tpo2_args; + } + + ff_type get_type() const override + { + return ff_type_file; + } + + QVector get_cap() const override + { + /* TPO 2.x format can read tracks only */ + /* waypoints, tracks, routes */ + return { ff_cap_none, ff_cap_read, ff_cap_none }; + } + + void rd_init(const QString& fname) override + { + tpo_rd_init(fname); + } + void read() override + { + tpo_read(); + } + void rd_deinit() override + { + tpo_rd_deinit(); + } + +private: + /* Data Members */ + + QVector tpo2_args = {}; +}; + +class Tpo3Format : public Format, private TpoFormatBase +{ +public: + QVector* get_args() override + { + return &tpo3_args; + } + + ff_type get_type() const override + { + return ff_type_file; + } + + QVector get_cap() const override + { + /* TPO 3.x format can read waypoints/tracks/routes */ + /* waypoints, tracks, routes */ + return { ff_cap_read, ff_cap_read, ff_cap_read }; + } + + void rd_init(const QString& fname) override + { + tpo_rd_init(fname); + } + void read() override + { + tpo_read(); + } + void rd_deinit() override + { + tpo_rd_deinit(); + } + +private: + /* Data Members */ + + QVector tpo3_args = {}; +}; +#endif // TPO_H_INCLUDED_ diff --git a/vecs.cc b/vecs.cc index f35289088..41b5c6943 100644 --- a/vecs.cc +++ b/vecs.cc @@ -69,6 +69,7 @@ #include "src/core/logging.h" // for Warning, FatalMsg #include "subrip.h" // for SubripFormat #include "text.h" // for TextFormat +#include "tpo.h" // for Tpo2Format, Tpo3Format #include "unicsv.h" // for UnicsvFormat #include "vcf.h" // for VcfFormat #include "xcsv.h" // for XcsvStyle, XcsvFormat @@ -79,8 +80,6 @@ extern ff_vecs_t geo_vecs; extern ff_vecs_t ozi_vecs; #if MAXIMAL_ENABLED extern ff_vecs_t tpg_vecs; -extern ff_vecs_t tpo2_vecs; -extern ff_vecs_t tpo3_vecs; extern ff_vecs_t gpl_vecs; extern ff_vecs_t mtk_vecs; extern ff_vecs_t mtk_fvecs; @@ -123,8 +122,8 @@ struct Vecs::Impl { #if MAXIMAL_ENABLED LowranceusrFormat lowranceusr_fmt; LegacyFormat tpg_fmt {tpg_vecs}; - LegacyFormat tpo2_fmt {tpo2_vecs}; - LegacyFormat tpo3_fmt {tpo3_vecs}; + Tpo2Format tpo2_fmt; + Tpo3Format tpo3_fmt; #if SHAPELIB_ENABLED ShapeFormat shape_fmt; #endif -- 2.30.2